package com.dhcc.core.api.shiro;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import com.dhcc.core.api.config.properties.JwtProperties;
import com.dhcc.core.api.service.ITokenService;
import com.dhcc.core.framework.constant.Const;
import com.dhcc.core.framework.util.CommonUtil;
import com.dhcc.core.framework.util.SpringContextHolder;
import com.dhcc.core.modules.system.cache.permission.PermissionCache;
import com.dhcc.core.modules.system.cache.role.RoleCache;
import com.dhcc.core.modules.system.entity.User;
import com.dhcc.core.modules.system.service.IUserService;

/**
 * 无状态的Realm
 * 
 * @ClassName: ApiAuthorizingRealm
 * @Description: TODO
 * @author: cyf
 * @date: 2018年1月2日 上午10:07:33
 */
public class ApiAuthorizingRealm extends AuthorizingRealm {
    /**
     * 仅支持Token 类型的Token，
     * 那么如果在AuthcFilter类中返回的是UsernamePasswordToken，那么将会报如下错误信息： Please
     * ensure that the appropriate Realm implementation is configured correctly
     * or that the realm accepts AuthenticationTokens of this
     * type.AuthcFilter.isAccessAllowed()
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof ApiAuthenticationToken;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
            throws AuthenticationException {
        // 身份认证方法
        String token = (String) authcToken.getCredentials();
        if (CommonUtil.isEmpty(token)) {
            throw new AuthenticationException("token为空!");
        }
        String jwtToken = null;
        // 去JWT头部分
        JwtProperties jwtProperties = SpringContextHolder.getBean(JwtProperties.class);
        int tokenTypeLength = jwtProperties.getTokenType().length() + 1;
        if ((token.length() > tokenTypeLength) && token.startsWith(jwtProperties.getTokenType() + " ")) {
            jwtToken = token.substring(tokenTypeLength);
        }

        ITokenService tokenService = SpringContextHolder.getBean("tokenService");
        // 验证token
        tokenService.verifyToken(jwtToken, false);

        // 解密获得userId，用于和数据库进行对比
        IUserService userService = SpringContextHolder.getBean("userService");
        Long userId = tokenService.getUserId(jwtToken);
        User user = userService.selectById(userId);

        // 查询用户信息
        if (user == null) {
            throw new AuthenticationException("用户不存在!");
        }

        // 判断用户状态
        if (user.getStatus() != 1) {
            throw new AuthenticationException("账号已被锁定,请联系管理员!");
        }

        // 填充用户部门角色信息
        user.fill();

        return new SimpleAuthenticationInfo(user, token, getName());
    }

    /**
     * 权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        User user = (User) principals.getPrimaryPrincipal();
        Set<String> permissionSet = new HashSet<>();
        Set<String> roleCodes = new HashSet<>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            roleCodes.add(Const.ADMIN_NAME);
            roleCodes.add(Const.EVERYONE_NAME);
            permissionSet.add("*:*:*");
        } else {
            List<Long> roleIds = user.getRoleIds();
            roleIds.add(Const.EVERYONE_ROLE_ID);// everyone角色
            List<Long> deptIds = user.getDeptIds();

            // 角色的权限
            for (Long roleId : roleIds) {
                List<String> permissions = PermissionCache.me().findPermissionsByPrincipalId(roleId);
                if (permissions != null) {
                    for (String permission : permissions) {
                        if (CommonUtil.isNotEmpty(permission)) {
                            permissionSet.add(permission);
                        }
                    }
                }
                String roleCode = RoleCache.me().getRoleCodeById(roleId);
                roleCodes.add(roleCode);
            }
            // 部门的权限
            for (Long deptId : deptIds) {
                List<String> permissions = PermissionCache.me().findPermissionsByPrincipalId(deptId);
                if (permissions != null) {
                    for (String permission : permissions) {
                        if (CommonUtil.isNotEmpty(permission)) {
                            permissionSet.add(permission);
                        }
                    }
                }
            }
            // 用户个人的权限
            List<String> permissions = PermissionCache.me().findPermissionsByPrincipalId(user.getId());
            if (permissions != null) {
                for (String permission : permissions) {
                    if (CommonUtil.isNotEmpty(permission)) {
                        permissionSet.add(permission);
                    }
                }
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(permissionSet);
        info.addRoles(roleCodes);
        return info;
    }
}